package com.pluszg.nutrition.common.utils.json;

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import com.pluszg.nutrition.common.bean.ApplicationConstants;
import com.pluszg.nutrition.common.bean.EnumDatePattern;
import com.pluszg.nutrition.common.exception.PlusException;
import com.pluszg.nutrition.common.utils.json.serializer.DateSerializer;
import com.pluszg.nutrition.common.utils.json.serializer.LongSerializer;
import lombok.NoArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder;

import java.io.IOException;
import java.util.Date;
import java.util.Objects;

import static lombok.AccessLevel.PRIVATE;

@Slf4j
@NoArgsConstructor(access = PRIVATE)
public class JsonUtil {

    private static ObjectMapper mapper;

    static {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        //自定义Long类型转换 超过12个数字用String格式返回，由于js的number只能表示15个数字
        builder.serializerByType(Long.class, new LongSerializer());
        builder.serializerByType(Long.TYPE, new LongSerializer());

        //自定义日期类型转换
        String pattern = EnumDatePattern.DEFAULT_PATTERN.desc();
        builder.serializerByType(Date.class, new DateSerializer(pattern));
        //防止feign日期转换失败
        builder.simpleDateFormat(pattern);

        //是否缩放排列输出，默认false
        // builder.indentOutput(true);
        builder.timeZone(ApplicationConstants.APP_TIMEZONE);

        builder.modules(
                //识别Java8时间
                new ParameterNamesModule(),
                new Jdk8Module(),
                new JavaTimeModule()
        );

        //启用
        builder.featuresToEnable(
                DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, //允许单个数值当做数组处理
                DeserializationFeature.FAIL_ON_NUMBERS_FOR_ENUMS, //禁止使用int代表Enum的order()來反序列化Enum, 抛出异常
                JsonParser.Feature.ALLOW_SINGLE_QUOTES //识别单引号
        );
        mapper = builder.build();
    }

    public static ObjectMapper getMapper() {
        return mapper;
    }

    public static String toJSONString(Object object) {
        if (Objects.nonNull(object)) {
            try {
                return mapper.writeValueAsString(object);
            } catch (JsonProcessingException e) {
                log.error("Failed to write value as json string.{}", e.getMessage());
                throw new PlusException("转换json字符串失败");
            }
        }
        return null;
    }

    /**
     * 格式化输出内容
     *
     * @param object
     * @return
     */
    public static String format2JsonStr(Object object) {
        if (Objects.nonNull(object)) {
            try {
                if (object instanceof String) {
                    String str = (String) object;
                    if (isJson(str)) {
                        object = mapper.readValue(str, Object.class);
                    }
                }
                return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);
            } catch (Exception e) {
                log.error("Failed to write value as format json string.{}", e.getMessage());
                throw new PlusException("转换json字符串失败");
            }
        }
        return null;
    }

    public static <T> T jsonStrToBean(String jsonStr, Class<T> clazz) {
        if (StringUtils.isNotBlank(jsonStr) && Objects.nonNull(clazz)) {
            try {
                return mapper.readValue(jsonStr, clazz);
            } catch (IOException e) {
                log.error("Failed to convert json string to java bean.{}", e.getMessage());
                throw new PlusException("json字符串转换java对象失败");
            }
        }
        return null;
    }

    public static <T> T readValue(String jsonStr, TypeReference<T> reference) {
        if (StringUtils.isNotBlank(jsonStr) && Objects.nonNull(reference)) {
            try {
                return mapper.readValue(jsonStr, reference);
            } catch (Exception e) {
                log.error("Failed to read json string value.", e);
                throw new PlusException(e.getMessage());
            }
        }
        return null;
    }

    public static boolean isJson(String jsonStr) {
        if (StringUtils.isNotBlank(jsonStr)) {
            try {
                mapper.readTree(jsonStr);
                return true;
            } catch (IOException e) {
                log.error("Failed to read tree.{}", e.getMessage());
            }
        }
        return false;
    }
}
